﻿using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using HtmlAgilityPack;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Mvc.RazorTools.Tests
{
	[TestClass]
	public class MvcRazorObjectTests
	{
		[TestMethod]
		[TestCategory("MvcRazorObjectTests")]
		public void ConstructorTest1()
		{
			TestObject item = new TestObject();

			Assert.AreEqual(TestObject.TestConstants.IdValue, item.Id);
			Assert.AreEqual(TestObject.TestConstants.Name, item.Name);
			Assert.AreEqual(TestObject.TestConstants.HtmlTag, item.HtmlTag);
			Assert.AreEqual(false, item.Locked);

			HtmlNode node = item.HtmlNode();
			Assert.AreEqual(true, node.Attributes.Contains(TestObject.TestConstants.IdName));
			Assert.AreEqual(TestObject.TestConstants.IdValue, node.Attributes[TestObject.TestConstants.IdName].Value);
		}

		[TestMethod]
		[TestCategory("MvcRazorObjectTests")]
		public void ConstructorTest2()
		{
			TestObject item = new TestObject("MyId");

			Assert.AreEqual("MyId", item.Id);
			Assert.AreEqual(TestObject.TestConstants.Name, item.Name);
			Assert.AreEqual(TestObject.TestConstants.HtmlTag, item.HtmlTag);
			Assert.AreEqual(false, item.Locked);

			HtmlNode node = item.HtmlNode();
			Assert.AreEqual(true, node.Attributes.Contains(TestObject.TestConstants.IdName));
			Assert.AreEqual("MyId", node.Attributes[TestObject.TestConstants.IdName].Value);
		}

		[TestMethod]
		[TestCategory("MvcRazorObjectTests")]
		public void AddClassAttributeWithKeyTest()
		{
			TestObject item = new TestObject();
			item.AddClassAttribute("key1", "value1");

			if (item.ClassAttributes.ContainsKey("key1"))
			{
				Assert.AreEqual("value1", item.ClassAttributes["key1"]);
				Assert.AreEqual(TestObject.TestConstants.IdValue, item.Id);
				Assert.AreEqual(TestObject.TestConstants.Name, item.Name);
				Assert.AreEqual(TestObject.TestConstants.HtmlTag, item.HtmlTag);
				Assert.AreEqual(false, item.Locked);

				HtmlNode node = item.HtmlNode();
				Assert.AreEqual(true, node.Attributes.Contains(TestObject.TestConstants.IdName));
				Assert.AreEqual(TestObject.TestConstants.IdValue, node.Attributes[TestObject.TestConstants.IdName].Value);
				Assert.AreEqual(true, node.Attributes.Contains("class"));
				Assert.AreEqual("value1", node.Attributes["class"].Value);
			}
			else
			{
				Assert.Fail();
			}
		}

		[TestMethod]
		[TestCategory("MvcRazorObjectTests")]
		public void AddClassAttributeTest()
		{
			TestObject item = new TestObject();
			item.AddClassAttribute("key1");

			if (item.ClassAttributes.ContainsKey("key1"))
			{
				Assert.AreEqual("key1", item.ClassAttributes["key1"]);
				Assert.AreEqual(TestObject.TestConstants.IdValue, item.Id);
				Assert.AreEqual(TestObject.TestConstants.Name, item.Name);
				Assert.AreEqual(TestObject.TestConstants.HtmlTag, item.HtmlTag);
				Assert.AreEqual(false, item.Locked);

				HtmlNode node = item.HtmlNode();
				Assert.AreEqual(true, node.Attributes.Contains(TestObject.TestConstants.IdName));
				Assert.AreEqual(TestObject.TestConstants.IdValue, node.Attributes[TestObject.TestConstants.IdName].Value);
				Assert.AreEqual(true, node.Attributes.Contains("class"));
				Assert.AreEqual("key1", node.Attributes["class"].Value);
			}
			else
			{
				Assert.Fail();
			}
		}

		[TestMethod]
		[TestCategory("MvcRazorObjectTests")]
		public void UpdateClassAttributeWithKeyTest()
		{
			TestObject item = new TestObject();
			item.AddClassAttribute("key1", "value1");
			item.UpdateClassAttribute("key1", "value2");

			if (item.ClassAttributes.ContainsKey("key1"))
			{
				Assert.AreEqual("value2", item.ClassAttributes["key1"]);
				Assert.AreEqual(TestObject.TestConstants.IdValue, item.Id);
				Assert.AreEqual(TestObject.TestConstants.Name, item.Name);
				Assert.AreEqual(TestObject.TestConstants.HtmlTag, item.HtmlTag);
				Assert.AreEqual(false, item.Locked);

				HtmlNode node = item.HtmlNode();
				Assert.AreEqual(true, node.Attributes.Contains(TestObject.TestConstants.IdName));
				Assert.AreEqual(TestObject.TestConstants.IdValue, node.Attributes[TestObject.TestConstants.IdName].Value);
				Assert.AreEqual(true, node.Attributes.Contains("class"));
				Assert.AreEqual("value2", node.Attributes["class"].Value);
			}
			else
			{
				Assert.Fail();
			}
		}

		[TestMethod]
		[TestCategory("MvcRazorObjectTests")]
		public void UpdateClassAttributeTest()
		{
			TestObject item = new TestObject();
			item.AddClassAttribute("key1");
			item.UpdateClassAttribute("key1", "value2");

			if (item.ClassAttributes.ContainsKey("key1"))
			{
				Assert.AreEqual("value2", item.ClassAttributes["key1"]);
				Assert.AreEqual(TestObject.TestConstants.IdValue, item.Id);
				Assert.AreEqual(TestObject.TestConstants.Name, item.Name);
				Assert.AreEqual(TestObject.TestConstants.HtmlTag, item.HtmlTag);
				Assert.AreEqual(false, item.Locked);

				HtmlNode node = item.HtmlNode();
				Assert.AreEqual(true, node.Attributes.Contains(TestObject.TestConstants.IdName));
				Assert.AreEqual(TestObject.TestConstants.IdValue, node.Attributes[TestObject.TestConstants.IdName].Value);
				Assert.AreEqual(true, node.Attributes.Contains("class"));
				Assert.AreEqual("value2", node.Attributes["class"].Value);
			}
			else
			{
				Assert.Fail();
			}
		}

		[TestMethod]
		[TestCategory("MvcRazorObjectTests")]
		public void MergeClassAttributes1()
		{
			TestObject item = new TestObject();
			item.ClassAttributes.Add("item1", "value1");
			item.ClassAttributes.Add("item2", "value2");
			item.ClassAttributes.Add("item3", "value3");

			Dictionary<string, string> classAttributes = new Dictionary<string, string>();
			item.UpdateClassAttribute("item2", "value7");
			classAttributes.Add("item4", "value4");
			classAttributes.Add("item5", "value5");
			classAttributes.Add("item6", "value6");
			item.MergeClassAttributes(classAttributes);

			Assert.AreEqual(6, item.ClassAttributes.Count());
			Assert.AreEqual(true, item.ClassAttributes.ContainsKey("item1"));
			Assert.AreEqual(true, item.ClassAttributes.ContainsKey("item2"));
			Assert.AreEqual(true, item.ClassAttributes.ContainsKey("item3"));
			Assert.AreEqual(true, item.ClassAttributes.ContainsKey("item4"));
			Assert.AreEqual(true, item.ClassAttributes.ContainsKey("item5"));
			Assert.AreEqual(true, item.ClassAttributes.ContainsKey("item6"));
			Assert.AreEqual("value1", item.ClassAttributes["item1"]);
			Assert.AreEqual("value7", item.ClassAttributes["item2"]);
			Assert.AreEqual("value3", item.ClassAttributes["item3"]);
			Assert.AreEqual("value4", item.ClassAttributes["item4"]);
			Assert.AreEqual("value5", item.ClassAttributes["item5"]);
			Assert.AreEqual("value6", item.ClassAttributes["item6"]);

			HtmlNode node = item.HtmlNode();
			Assert.AreEqual(true, node.Attributes.Contains(TestObject.TestConstants.IdName));
			Assert.AreEqual(TestObject.TestConstants.IdValue, node.Attributes[TestObject.TestConstants.IdName].Value);
			Assert.AreEqual(true, node.Attributes.Contains("class"));
			Assert.AreEqual(true, node.Attributes["class"].Value.Contains("value1"));
			Assert.AreEqual(true, node.Attributes["class"].Value.Contains("value7"));
			Assert.AreEqual(true, node.Attributes["class"].Value.Contains("value3"));
			Assert.AreEqual(true, node.Attributes["class"].Value.Contains("value4"));
			Assert.AreEqual(true, node.Attributes["class"].Value.Contains("value5"));
			Assert.AreEqual(true, node.Attributes["class"].Value.Contains("value6"));
		}

		[TestMethod]
		[TestCategory("MvcRazorObjectTests")]
		public void MergeClassAttributes2()
		{
			TestObject item = new TestObject();
			item.ClassAttributes.Add("item1", "value1");
			item.ClassAttributes.Add("item2", "value2");
			item.ClassAttributes.Add("item3", "value3");

			Assert.AreEqual(3, item.ClassAttributes.Count());
			Assert.AreEqual(true, item.ClassAttributes.ContainsKey("item1"));
			Assert.AreEqual(true, item.ClassAttributes.ContainsKey("item2"));
			Assert.AreEqual(true, item.ClassAttributes.ContainsKey("item3"));
			Assert.AreEqual("value1", item.ClassAttributes["item1"]);
			Assert.AreEqual("value2", item.ClassAttributes["item2"]);
			Assert.AreEqual("value3", item.ClassAttributes["item3"]);

			HtmlNode node = item.HtmlNode();
			Assert.AreEqual(true, node.Attributes.Contains(TestObject.TestConstants.IdName));
			Assert.AreEqual(TestObject.TestConstants.IdValue, node.Attributes[TestObject.TestConstants.IdName].Value);
			Assert.AreEqual(true, node.Attributes.Contains("class"));
			Assert.AreEqual(true, node.Attributes["class"].Value.Contains("value1"));
			Assert.AreEqual(true, node.Attributes["class"].Value.Contains("value2"));
			Assert.AreEqual(true, node.Attributes["class"].Value.Contains("value3"));
		}

		[TestMethod]
		[TestCategory("MvcRazorObjectTests")]
		public void BaseImplicitCastToMvcHtmlString()
		{
			TestObject item = new TestObject();
			MvcHtmlString s = item;
			Assert.AreEqual(item.Html.ToString(), s.ToString());
		}

		[TestMethod]
		[TestCategory("MvcRazorObjectTests")]
		public void BaseImplicitCastToString()
		{
			TestObject item = new TestObject();
			string s = item;
			Assert.AreEqual(item.Html.ToString(), s);
		}

		[TestMethod]
		[TestCategory("MvcRazorObjectTests")]
		[ExpectedException(typeof(ModifyLockedInstanceException))]
		public void SetIdWhenLockedTest()
		{
			TestObject item = new TestObject();
			item.Locked = true;
			item.Id = "newId";
		}

		[TestMethod]
		[TestCategory("MvcRazorObjectTests")]
		[ExpectedException(typeof(ModifyLockedInstanceException))]
		public void SetNameWhenLockedTest()
		{
			TestObject item = new TestObject();
			item.Locked = true;
			item.Name = "newName";
		}

		[TestMethod]
		[TestCategory("MvcRazorObjectTests")]
		[ExpectedException(typeof(ModifyLockedInstanceException))]
		public void SetUnlockedWhenLockedTest()
		{
			TestObject item = new TestObject();
			item.Locked = true;
			item.Locked = false;
		}

		[TestMethod]
		[TestCategory("MvcRazorObjectTests")]
		public void SetHtmlTagTest()
		{
			TestObject item = new TestObject();
			item.HtmlTag = "div";

			Assert.AreEqual("div", item.HtmlNode().Name);
		}

		[TestMethod]
		[TestCategory("MvcRazorObjectTests")]
		public void IncludeIdInHtmlTest()
		{
			TestObject item = new TestObject("MyId");
			item.IncludeIdInHtml = false;

			Assert.AreEqual("MyId", item.Id);
			Assert.AreEqual(TestObject.TestConstants.Name, item.Name);
			Assert.AreEqual(TestObject.TestConstants.HtmlTag, item.HtmlTag);
			Assert.AreEqual(false, item.Locked);
			Assert.AreEqual(false, item.IncludeIdInHtml);

			HtmlNode node = item.HtmlNode();
			Assert.AreEqual(0, node.Attributes.Count());
		}

		[TestMethod]
		[TestCategory("MvcRazorObjectTests")]
		public void SetNameTest()
		{
			TestObject item = new TestObject();
			item.Name = "newName";

			Assert.AreEqual(TestObject.TestConstants.IdValue, item.Id);
			Assert.AreEqual("newName", item.Name);
			Assert.AreEqual(TestObject.TestConstants.HtmlTag, item.HtmlTag);
			Assert.AreEqual(false, item.Locked);

			HtmlNode node = item.HtmlNode();
			Assert.AreEqual(true, node.Attributes.Contains(TestObject.TestConstants.IdName));
			Assert.AreEqual(TestObject.TestConstants.IdValue, node.Attributes[TestObject.TestConstants.IdName].Value);
		}

		[TestMethod]
		[TestCategory("MvcRazorObjectTests")]
		public void SetIdTest()
		{
			TestObject item = new TestObject();
			item.Id = "newId";

			Assert.AreEqual("newId", item.Id);
			Assert.AreEqual(TestObject.TestConstants.Name, item.Name);
			Assert.AreEqual(TestObject.TestConstants.HtmlTag, item.HtmlTag);
			Assert.AreEqual(false, item.Locked);

			HtmlNode node = item.HtmlNode();
			Assert.AreEqual(true, node.Attributes.Contains(TestObject.TestConstants.IdName));
			Assert.AreEqual("newId", node.Attributes[TestObject.TestConstants.IdName].Value);
		}

		[TestMethod]
		[TestCategory("MvcRazorObjectTests")]
		public void CloneTest1()
		{
			TestObject item1 = new TestObject();
			object item2 = item1.Clone();

			Assert.IsInstanceOfType(item2, typeof(MvcRazorObject));
			Assert.AreNotSame(item1, item2);
			Assert.AreEqual(TestObject.TestConstants.IdValue, ((MvcRazorObject)item2).Id);
			Assert.AreEqual(TestObject.TestConstants.Name, ((MvcRazorObject)item2).Name);
			Assert.AreEqual(TestObject.TestConstants.HtmlTag, ((MvcRazorObject)item2).HtmlTag);
			Assert.AreEqual(false, ((MvcRazorObject)item2).Locked);

			HtmlNode node = item1.HtmlNode();
			Assert.AreEqual(true, node.Attributes.Contains(TestObject.TestConstants.IdName));
			Assert.AreEqual(TestObject.TestConstants.IdValue, node.Attributes[TestObject.TestConstants.IdName].Value);
		}

		[TestMethod]
		[TestCategory("MvcRazorObjectTests")]
		public void ToStringTest()
		{
			TestObject item = new TestObject();

			Assert.AreEqual(TestObject.TestConstants.IdValue, item.Id);
			Assert.AreEqual(TestObject.TestConstants.Name, item.Name);
			Assert.AreEqual(TestObject.TestConstants.HtmlTag, item.HtmlTag);
			Assert.AreEqual(false, item.Locked);

			HtmlNode node = item.HtmlNode(item.ToString());
			Assert.AreEqual(true, node.Attributes.Contains(TestObject.TestConstants.IdName));
			Assert.AreEqual(TestObject.TestConstants.IdValue, node.Attributes[TestObject.TestConstants.IdName].Value);
		}

		[TestMethod]
		[TestCategory("MvcRazorObjectTests")]
		public void AddAttributeTest()
		{
			TestObject item = new TestObject();
			item.AddAttribute("data-attr-1", "value1");
			item.AddAttribute("data-attr-2", "value2");
			item.AddAttribute("data-attr-3", "value3");

			HtmlNode node = item.HtmlNode();
			Assert.AreEqual(true, node.Attributes.Contains(TestObject.TestConstants.IdName));
			Assert.AreEqual(TestObject.TestConstants.IdValue, node.Attributes[TestObject.TestConstants.IdName].Value);
			Assert.AreEqual(true, node.Attributes.Contains("data-attr-1"));
			Assert.AreEqual("value1", node.Attributes["data-attr-1"].Value);
			Assert.AreEqual(true, node.Attributes.Contains("data-attr-2"));
			Assert.AreEqual("value2", node.Attributes["data-attr-2"].Value);
			Assert.AreEqual(true, node.Attributes.Contains("data-attr-3"));
			Assert.AreEqual("value3", node.Attributes["data-attr-3"].Value);
		}

		[TestMethod]
		[TestCategory("MvcRazorObjectTests")]
		public void UpdateAttributeTest()
		{
			TestObject item = new TestObject();
			item.AddAttribute("data-attr-1", "value1");
			item.AddAttribute("data-attr-2", "value2");
			item.AddAttribute("data-attr-3", "value3");
			item.UpdateAttribute("data-attr-2", "value4");

			HtmlNode node = item.HtmlNode();
			Assert.AreEqual(true, node.Attributes.Contains(TestObject.TestConstants.IdName));
			Assert.AreEqual(TestObject.TestConstants.IdValue, node.Attributes[TestObject.TestConstants.IdName].Value);
			Assert.AreEqual(true, node.Attributes.Contains("data-attr-1"));
			Assert.AreEqual("value1", node.Attributes["data-attr-1"].Value);
			Assert.AreEqual(true, node.Attributes.Contains("data-attr-2"));
			Assert.AreEqual("value4", node.Attributes["data-attr-2"].Value);
			Assert.AreEqual(true, node.Attributes.Contains("data-attr-3"));
			Assert.AreEqual("value3", node.Attributes["data-attr-3"].Value);
		}

		[TestMethod]
		[TestCategory("MvcRazorObjectTests")]
		public void MergeAttributesTest()
		{
			TestObject item = new TestObject();
			item.AddAttribute("data-attr-1", "value1");
			item.AddAttribute("data-attr-2", "value2");
			item.AddAttribute("data-attr-3", "value3");

			Dictionary<string, string> newItems = new Dictionary<string, string>();
			newItems.Add("data-attr-2", "value5");
			newItems.Add("data-attr-4", "value4");
			item.MergeAttributes(newItems);

			HtmlNode node = item.HtmlNode();
			Assert.AreEqual(true, node.Attributes.Contains(TestObject.TestConstants.IdName));
			Assert.AreEqual(TestObject.TestConstants.IdValue, node.Attributes[TestObject.TestConstants.IdName].Value);
			Assert.AreEqual(true, node.Attributes.Contains("data-attr-1"));
			Assert.AreEqual("value1", node.Attributes["data-attr-1"].Value);
			Assert.AreEqual(true, node.Attributes.Contains("data-attr-2"));
			Assert.AreEqual("value5", node.Attributes["data-attr-2"].Value);
			Assert.AreEqual(true, node.Attributes.Contains("data-attr-3"));
			Assert.AreEqual("value3", node.Attributes["data-attr-3"].Value);
			Assert.AreEqual(true, node.Attributes.Contains("data-attr-4"));
			Assert.AreEqual("value4", node.Attributes["data-attr-4"].Value);
		}

		[TestMethod]
		[TestCategory("MvcRazorObjectTests")]
		public void AddStyleTest()
		{
			TestObject item = new TestObject();
			item.AddStyle("height", "250px");
			item.AddStyle("width", "300px");
			item.AddStyle("backgroundColor", "#000000");

			HtmlNode node = item.HtmlNode();
			Assert.AreEqual(true, node.Attributes.Contains(TestObject.TestConstants.IdName));
			Assert.AreEqual(TestObject.TestConstants.IdValue, node.Attributes[TestObject.TestConstants.IdName].Value);
			Assert.AreEqual(true, node.Attributes.Contains("style"));
			Assert.AreEqual("height: 250px;width: 300px;backgroundColor: #000000;", node.Attributes["style"].Value);
		}

		[TestMethod]
		[TestCategory("MvcRazorObjectTests")]
		public void UpdateStyleTest()
		{
			TestObject item = new TestObject();
			item.AddStyle("height", "250px");
			item.AddStyle("width", "300px");
			item.AddStyle("backgroundColor", "#000000");
			item.UpdateStyle("backgroundColor", "#FFFFFF");

			HtmlNode node = item.HtmlNode();
			Assert.AreEqual(true, node.Attributes.Contains(TestObject.TestConstants.IdName));
			Assert.AreEqual(TestObject.TestConstants.IdValue, node.Attributes[TestObject.TestConstants.IdName].Value);
			Assert.AreEqual(true, node.Attributes.Contains("style"));
			Assert.AreEqual("height: 250px;width: 300px;backgroundColor: #FFFFFF;", node.Attributes["style"].Value);
		}

		[TestMethod]
		[TestCategory("MvcRazorObjectTests")]
		public void MergeStylesTest()
		{
			TestObject item = new TestObject();
			item.AddStyle("height", "250px");
			item.AddStyle("width", "300px");
			item.AddStyle("backgroundColor", "#000000");

			IDictionary<string, string> newStyles = new Dictionary<string, string>();
			newStyles.Add("border-color", "#123456");
			newStyles.Add("line-height", "10px");

			item.MergeStyles(newStyles);

			HtmlNode node = item.HtmlNode();
			string value = node.Attributes["style"].Value;

			Assert.AreEqual(true, node.Attributes.Contains(TestObject.TestConstants.IdName));
			Assert.AreEqual(TestObject.TestConstants.IdValue, node.Attributes[TestObject.TestConstants.IdName].Value);
			Assert.AreEqual(true, node.Attributes.Contains("style"));
			Assert.AreEqual("height: 250px;width: 300px;backgroundColor: #000000;border-color: #123456;line-height: 10px;", node.Attributes["style"].Value);
		}
	}
}
